home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / csrc1.arc / COOBLD.C < prev    next >
C/C++ Source or Header  |  1989-07-27  |  13KB  |  553 lines

  1. #
  2. /*
  3.  * coobld
  4.  *
  5.  */
  6.  
  7. /*)BUILD
  8. */
  9.  
  10. #ifdef    DOCUMENTATION
  11.  
  12. title    coobld    Build Cookie Data File
  13. index        Build cookie data file
  14.  
  15. synopsis
  16.  
  17.     coobld    [options] file_list
  18.  
  19. description
  20.  
  21.  
  22.     Build the internal data file for fortune cookies.
  23.     If no file argument is given, the file "cookie.txt"
  24.     will be looked for on the current account.  The file_list
  25.     may contain wild-cards.
  26.     .s
  27.     The following options are defined:
  28.     .lm +8
  29.     .s.i -8;-d    Debug
  30.     .s.i -8;-v    Verify (print each cookie line as it is read)
  31.  
  32. Cookie File Format
  33.  
  34.     Cookie text files have the following format:
  35.     .nf
  36.         Each cookie is terminated by a line containing
  37.         "%%" in column 1 and 2.
  38.         %%
  39.           By default, a cookie that starts with one
  40.           or more spaces is considered to be a "poem"
  41.           and will not be reformatted.
  42.         %%
  43.         To attribute a cookie. terminate it by
  44.         terminating the sentence with a '.', '?',
  45.         or '!' then append the author's name as shown.
  46.                     -- Author's name.
  47.         It is recommended that author's names start in
  48.         column 48 where possible.  Note that the cookie
  49.         may continue, which allows adding footnotes or
  50.         rebuttals.
  51.         %%
  52.     .s.f
  53.     Cookies are stored on a disk file in a format compatible
  54.     with the limited amount of random access capabilities available
  55.     on "standard" C libraries.  The format is, of course, called
  56.     "Cookie access method."  The output file is written by fwrite()
  57.     and must be read by fread().
  58.     .s
  59.     The cookie file has the following format:
  60.     .s.nf
  61.     Record 1:
  62.       long    ncookie;    /* number of cookies    */
  63.       int    nindex;        /* Index table size    */
  64.       int    subindex;    /* How many subindexes    */
  65.       int    sindex;        /* sizeof index table    */
  66.       char    date[26];    /* When file created    */
  67.     .s
  68.     Record 2:
  69.       long    main_index[tabdim];
  70.                 /* Seek location for    */
  71.                 /* each subindex entry    */
  72.     .s
  73.     Record 3 .. tabdim+2
  74.       long    sub_index[tabdim];
  75.                  /* Cookie seek address    */
  76.     .s
  77.     Cookie records have just plain text, one space between words.
  78.     Each cookie is terminated by a line containing "%%".
  79.     .s
  80.     Thus, to find cookie N, proceed as follows:
  81.     .s.nf
  82.         Read record 1.
  83.         Allocate space for index[].
  84.         Read record 2 into index.
  85.     .s
  86.         Read index[N / ncookies] into index.
  87.         Read from index[N % ncookies].
  88.     .s.f
  89.     Note: if the maximum cookie contains 2047 bytes, the index table
  90.     may be dimensioned (2047 / sizeof (long)) (== 256) and the maximum
  91.     number of cookies equals 256 * 256 == 65536.  If this is done, and
  92.     only one cookie is to be read, only one buffer is needed, defined as:
  93.     .s.nf
  94.         union {
  95.           char    text[TEXTSIZE];
  96.           long    index[TEXTSIZE / sizeof (long)];
  97.         } cookie;
  98.  
  99. author
  100.  
  101.     Martin Minow
  102.  
  103. bugs
  104.  
  105.     probably.
  106.  
  107. #endif
  108.  
  109. #include <stdio.h>
  110. #define    TRUE    1
  111. #define    FALSE    0
  112. #define    EOS    0
  113. #ifdef    rsx
  114. #define    R_MODE    "run"
  115. #define    W_MODE    "wun"
  116. #else
  117. #ifdef    rt11
  118. #define    R_MODE    "rn"
  119. #define    W_MODE    "wn"
  120. #else
  121. #define    R_MODE    "r"
  122. #define    W_MODE    "w"
  123. #endif
  124. #endif
  125.  
  126. #define    SIGNAL    '%'
  127.  
  128. extern long    ftell();
  129.  
  130. FILE    *indexfp;        /* Indexes stored here        */
  131. FILE    *dummyfp;        /* Dummy output file        */
  132. FILE    *outfp;            /* Output file (cookie.fil)    */
  133.  
  134. #define    INPUT_FILE    "cookie.txt"
  135.  
  136. /*
  137.  * The following may need work on RT11 to insert file sizes
  138.  */
  139.  
  140. char    *text_file    = "ctext.tmp";
  141. char    *dummy_file    = "cdummy.tmp";
  142. char    *index_file    = "cindex.tmp";
  143. char    *cookie_file    = "cookie.fil";
  144.  
  145. struct header {
  146.     long    ncookie;    /* Number of cookies        */
  147.     int    nindex;        /* Dimension of top_index[]    */
  148.     int    subindex;    /* Number of subindex entries    */
  149.     int    sindex;        /* Sizeof index for alloc    */
  150.     char    date[28];    /* Date cookie file built    */
  151. } header;
  152.  
  153. char    text[513];        /* Working text            */
  154. long    *sub_index;         /* Indexes stored here        */
  155. long    *top_index;        /* Top level indexes go here    */
  156. long    firstindex;        /* -> top index in indexfp    */
  157. long    firstcookie;        /* -> first cookie in dummyfp    */
  158. int    verbose        = 0;
  159. int    debug        = 0;
  160.  
  161. main(argc, argv)
  162. int     argc;
  163. char    *argv[];
  164. {
  165.     register char    *ap;
  166.     register int    i;
  167.     int        nfiles;
  168.     FILE        *file_open();
  169.  
  170.     nfiles = 0;
  171.     for (i = 1; i < argc; i++) {
  172.         ap = argv[i];
  173.         if (*ap++ == '-') {
  174.         argv[i] = NULL;
  175.         for (; *ap != EOS; ap++) {
  176.             switch (tolower(*ap)) {
  177.  
  178.             case 'd':
  179.             debug++;
  180.             break;
  181.  
  182.             case 'v':
  183.             verbose++;
  184.             break;
  185.  
  186.             default:
  187.             fprintf(stderr, "?Unknown option '%c'\n", *ap);
  188.             }
  189.         }
  190.         }
  191.         else {
  192.         nfiles++;
  193.         }
  194.     }
  195.     
  196.     /*
  197.      * Copy raw cookies to a temp file.  Collect how many and
  198.       * dimension of indexes.
  199.      */
  200.     if (nfiles == 0) {
  201.         argc = 2;
  202.         argv[1] = INPUT_FILE;
  203.     }
  204.     maketext(argc, argv);
  205.     /*
  206.      * Build dummy cookie file
  207.      */
  208.     dummyfp = file_open(dummy_file, W_MODE);
  209.     indexfp = file_open(index_file, W_MODE);
  210.     makedummy(argc, argv);
  211.     fclose(dummyfp);
  212.     fclose(indexfp);
  213.     /*
  214.      * Build real cookie file
  215.      */
  216.     outfp = file_open(cookie_file,  W_MODE);
  217.     dummyfp = file_open(dummy_file, R_MODE);
  218.     indexfp = file_open(index_file, R_MODE);
  219.     makecookie();
  220.     fclose(outfp);
  221.     cdelete(dummyfp);
  222.     cdelete(indexfp);
  223. }
  224.  
  225. cdelete(fd)
  226. FILE        *fd;
  227. /*
  228.  * Close or delete the file
  229.  */
  230. {
  231.     char    work[40];
  232.  
  233.     if (debug)
  234.         fclose(fd);
  235.     else {
  236.         fgetname(fd, work);
  237.         fclose(fd);
  238.         delete(work);
  239.     }
  240. }
  241.  
  242. FILE *
  243. file_open(filename, mode)
  244. char        *filename;
  245. char        *mode;
  246. /*
  247.  * Open the file, die if failure
  248.  */
  249. {
  250.     register FILE    *fd;
  251.  
  252.     if ((fd = fopen(filename, mode)) == NULL) {
  253.         perror(filename);
  254.         error("?COOBLD-F-Can't %s \"%s\"\n",
  255.         (*mode == 'w') ? "create" : "open", filename);
  256.     }
  257.     return(fd);
  258. }
  259.  
  260. maketext(argc, argv)
  261. int        argc;
  262. char        *argv[];
  263. /*
  264.  * Read files obtaining the counts.
  265.  *
  266.  *    Header is set as follows:
  267.  *
  268.  *        header.ncookie        Number of cookies (long)
  269.  *        header.nindex        Index dimension
  270.  *        header.subindex        Number of subindex entries
  271.  *        header.sindex        Sizeof index[]
  272.  *        header.date        ctime()
  273.  */
  274. {
  275.     register int        len;
  276.     long            subsquare;
  277.     char            *cpystr();
  278.     register int        bigbytes;    /* Longest record bytes    */
  279.     int            tvec[2];
  280.     FILE            *infd;
  281.     register int        nfiles;
  282.     int            i;
  283.     int            nrecords;
  284.  
  285.     bigbytes = 0;
  286.     time(&tvec);
  287.     cpystr(&header.date, ctime(&tvec));
  288.     header.ncookie = 0;
  289.     header.nindex = 0;
  290.     subsquare = 0;
  291.     len = 0;
  292.     /*
  293.      * Read all cookies to count them and get the max. length.
  294.      */
  295.     for (i = 1; i < argc; i++) {
  296.         if (argv[i] == NULL)
  297.         continue;
  298.         if ((infd = fwild(argv[i], "r")) == NULL) {
  299.         perror(argv[i]);
  300.         continue;
  301.         }
  302.         for (nfiles = 0; fnext(infd); nfiles++) {
  303.         fgetname(infd, text);
  304.         printf("%s:", text);
  305.         nrecords = 0;
  306.         while (!feof(infd)) {
  307.             fgets(text, sizeof text, infd);
  308.             nrecords++;
  309.             if (feof(infd)
  310.              || (text[0] == SIGNAL && text[1] == SIGNAL)) {
  311.             if (len == 0)
  312.                 continue;
  313.             if (len > bigbytes)
  314.                 bigbytes = len;
  315.             len = 0;
  316.             header.ncookie++;
  317.             if (subsquare < header.ncookie) {
  318.                 header.nindex++;
  319.                 subsquare = header.nindex * header.nindex;
  320.             }
  321.             }
  322.             else {
  323.             len += strlen(text) + 2;
  324.             }
  325.         }
  326.         printf("\t%d\n", nrecords);
  327.         }
  328.         if (nfiles == 0) {
  329.         printf("No files match \"%s\"\n", argv[i]);
  330.         }
  331.     }
  332.     header.subindex = (header.ncookie + header.nindex - 1) / header.nindex;
  333.     header.sindex = header.nindex * sizeof (long);
  334.     printf("%ld cookies read, the longest has %d bytes\n",
  335.         header.ncookie, bigbytes);
  336.     printf("top index = %d, sub index = %d, index area size = %d\n",
  337.         header.nindex, header.subindex, header.sindex);
  338. }
  339.  
  340. makedummy(argc, argv)
  341. int        argc;
  342. char        *argv[];
  343. /*
  344.  * Build a dummy cookie file in two separate files:
  345.  *    dummyfp        Gets the cookie data
  346.  *    indexfp        Gets the indices.
  347.  *
  348.  * This way, we don't have to reposition the file, nor do we
  349.  * have to read and write the same file.
  350.  */
  351. {
  352.     register int    subi;        /* Index into sub_index[]    */
  353.     register int    topi;        /* Index into top_index[]    */
  354.     register int    len;        /* Input record length        */
  355.     int        i;
  356.     FILE        *infd;
  357.     long        count;
  358.     long        dummy_loc;
  359.  
  360.     count = 0;
  361.     if ((top_index = calloc(header.sindex, 1)) == NULL
  362.      || (sub_index = calloc(header.sindex, 1)) == NULL)
  363.         error("Can't allocate index buffers -- %d bytes\n", header.sindex);
  364.     put(&header, sizeof header, dummyfp, "dummy header");
  365.     put(&header, sizeof header, indexfp, "index header");
  366.     put(sub_index, header.sindex, dummyfp, "dummy top index");
  367.     put(sub_index, header.sindex, indexfp, "index top index");
  368.     firstindex = ftell(indexfp);
  369.     for (subi = header.subindex; --subi >= 0;) {
  370.         put(sub_index, header.sindex, dummyfp, "dummy sub index");
  371.     }
  372.     dummy_loc = firstcookie = ftell(dummyfp);
  373.     subi = 0;
  374.     topi = 0;
  375.     len = 0;
  376.     for (i = 1; i < argc; i++) {
  377.         if (argv[i] == NULL)
  378.         continue;
  379.         if ((infd = fwild(argv[i], "r")) == NULL)
  380.         continue;
  381.         while (fnext(infd) != NULL) {
  382.         while (!feof(infd)) {
  383.             if (fgets(text, sizeof text, infd) == NULL
  384.              || (text[0] == '%' && text[1] == '%')) {
  385.             if (len == 0)
  386.                 continue;
  387.             len = 0;
  388.             count++;
  389.             if (subi >= header.nindex) {
  390.                 if (topi >= header.nindex) {
  391.                 error("Too many cookies, max is %d ** 2\n",
  392.                     header.nindex);
  393.                 }
  394.                 top_index[topi] = ftell(indexfp);
  395.                 topi++;
  396.                 put(sub_index, header.sindex, indexfp, "sub index");
  397.                 subi = 0;
  398.             }
  399.             sub_index[subi] = dummy_loc;
  400.             subi++;
  401. #ifdef    rsx
  402.             fput("%%\n", 4, dummyfp);
  403. #else
  404.             fputs("%%\n", dummyfp);
  405. #endif
  406.             dummy_loc = ftell(dummyfp);
  407.             }
  408.             else {
  409. #ifdef    rsx
  410.             fput(text, strlen(text) + 1, dummyfp);
  411. #else
  412.             fputs(text, dummyfp);
  413. #endif
  414.             len += strlen(text);
  415.             }
  416.             if (ferror(dummyfp)) {
  417.             perror("writing text to temp file");
  418.             error("Output error");
  419.             }
  420.         }
  421.         }
  422.     }
  423.     /*
  424.      * Put the last subindex record
  425.      */
  426.     while (subi < header.nindex) {
  427.         sub_index[subi] = -1;
  428.         subi++;
  429.     }
  430.     top_index[topi] = ftell(indexfp);
  431.     topi++;
  432.     put(sub_index, header.sindex, indexfp, "last sub index");
  433.     while (topi < header.nindex) {
  434.         top_index[topi] = -1;
  435.         topi++;
  436.     }
  437.     printf("Work files built, %ld cookies, %d index levels\n",
  438.         count, header.nindex);
  439.     if (count != header.ncookie)
  440.         error("Expected %ld cookies, read %ld\n", header.ncookie, count);
  441. }
  442.  
  443. makecookie()
  444. /*
  445.  * Write outfp with cookie file, using
  446.  *
  447.  *    indexfp        Index file (has sub-indexes)
  448.  *    dummyfp        Cookie work file
  449.  *
  450.  */
  451. {
  452.     register int    i;
  453.     register int    bytect;
  454.     long        itemct;
  455.  
  456.     put(&header, sizeof header, outfp, "cookie header");
  457.     put(top_index, header.sindex, outfp, "cookie top index");
  458.     itemct = 0;
  459.     if (fseek(indexfp, firstindex, 0) != 0)
  460.         error("Can't seek to %ld on index file\n", firstindex);
  461.     if (fseek(dummyfp, firstcookie, 0) != 0)
  462.         error("Can't seek to %ld on cookie file\n", firstcookie);
  463.     for (i = 0; i < header.subindex; i++) {
  464.         get(sub_index, header.sindex, indexfp, "sub index");
  465.         put(sub_index, header.sindex, outfp, "cookie sub index");
  466.     }
  467.     printf("%d index records written\n", header.nindex + 1);
  468. #ifdef    rsx
  469.     while (fget(text, sizeof text, dummyfp), !feof(dummyfp)) {
  470.         fput(text, strlen(text) + 1, outfp);
  471. #else
  472.     while (fgets(text, sizeof text, dummyfp) != NULL) {
  473.         fputs(text, outfp);
  474. #endif
  475.     }
  476.     if (ferror(outfp)) {
  477.         perror("writing output");
  478.         error("Output error");
  479.     }
  480. }
  481.  
  482. /*
  483.  * Raw I/O routines
  484.  */
  485.  
  486. get(whereto, size, fd, why)
  487. char        *whereto;        /* Where to read to        */
  488. int        size;            /* Buffer size            */
  489. FILE        *fd;            /* Input file descriptor    */
  490. char        *why;            /* Who is reading for error    */
  491. /*
  492.  * Read into the buffer.  Return the number of bytes read.
  493.  * All errors are fatal.
  494.  */
  495. {
  496.     register int    i;
  497.  
  498. #ifdef    rsx
  499.     if ((i = fget(whereto, size, fd)) != size || ferror(fd)) {
  500.         perror("coobld fget error");
  501.         error("Reading %s, expected %d bytes, read %d bytes\n",
  502.         why, size, i);
  503.     }
  504. #else
  505.     if ((i = fread(whereto, size, 1, fd)) != 1 || ferror(fd)) {
  506.         perror("coobld fread error");
  507.         error("Reading %s, expected 1 item, %d bytes, read %d items\n",
  508.         why, size, i);
  509.     }
  510. #endif
  511. }
  512.  
  513. put(wherefrom, size, fd, why)
  514. char        *wherefrom;        /* Where to write from        */
  515. int        size;            /* Number of bytes to write    */
  516. FILE        *fd;            /* Output file descriptor    */
  517. char        *why;            /* Who is writeing for error    */
  518. /*
  519.  * Write from the buffer. All errors are fatal.
  520.  */
  521. {
  522.     register int        i;
  523.  
  524. #ifdef    rsx
  525.     if ((i = fput(wherefrom, size, fd)) != size || ferror(fd)) {
  526.         perror("coobld fput error");
  527.         error("Error writing %d bytes to %s, %d bytes written\n",
  528.         size, why, i);
  529.     }
  530. #else
  531.     if ((i = fwrite(wherefrom, size, 1, fd)) != 1 || ferror(fd)) {
  532.         perror("coobld fwrite error");
  533.         error("Error writing 1 item of %d bytes to %s, %d items\n",
  534.         size, why, i);
  535.     }
  536. #endif
  537. }
  538.  
  539. /*
  540.  * For debugging only
  541.  */
  542.  
  543. dump(indextable, why)
  544. long    indextable[];
  545. char    *why;
  546. {
  547.     register int i;
  548.  
  549.     printf("\n%s\n", why);
  550.     for (i = 0; i < header.nindex; i++)
  551.         printf("%3d %ld\n", i, indextable[i]);
  552. }
  553.